package com.example.cloudgateway.auth;

import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.ReactiveAuthenticationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.common.exceptions.InvalidTokenException;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.server.resource.BearerTokenAuthenticationToken;
import reactor.core.publisher.Mono;

/**
 *认证管理器
 */
@Slf4j
@AllArgsConstructor
public class ReactiveCommonAuthenticationManager implements ReactiveAuthenticationManager {

    private final TokenStore tokenStore;

    @Override
    public Mono<Authentication> authenticate(Authentication authentication) {
        return Mono.justOrEmpty(authentication)
                    .filter(x -> x instanceof BearerTokenAuthenticationToken)
                    .cast(BearerTokenAuthenticationToken.class)
                    .map(BearerTokenAuthenticationToken::getToken)
                    .flatMap((token) -> {
                        log.info("access token:{}",token);
                        OAuth2AccessToken oAuth2AccessToken = this.tokenStore.readAccessToken(token);
                        if(oAuth2AccessToken == null){
                            return Mono.error(new InvalidTokenException("invalid access token"));
                        }
                        if (oAuth2AccessToken.isExpired()){
                            return Mono.error(new InvalidTokenException("access token expired"));
                        }
                        OAuth2Authentication oAuth2Authentication = this.tokenStore.readAuthentication(token);
                        if (oAuth2Authentication == null) {
                            return Mono.error(new InvalidTokenException("invalid authentication token"));
                        }

                        return Mono.just(oAuth2Authentication);
                    }).cast(Authentication.class);
    }
}
